﻿using System.Collections.Generic;
using BasicParts;
using System.Linq;

namespace ParallaxMachine
{
    public class ParallaxManager
    {
        #region Fields and Constructor
        /// <summary>A list of lists, sorted as a list of horizontal
        /// backgrounds in each list of vertical backgrounds.</summary>

        /// <summary>A list of lists, sorted as [x, y]. </summary>
        //public List<Background[,]> backgrounds;
        //public Dictionary<int, Vector2> layerSpeeds;

        public List<Layer> Background;
        public List<Layer> Foreground;

        /// <summary>
        /// Creates a new ParallaxService. Add backgrounds and assign values to 
        /// layerSpeeds, then call the UpdateBackgrounds(...) method.
        /// </summary>
        public ParallaxManager()
        {
            //backgrounds = new List<Background[,]>();
            //layerSpeeds = new Dictionary<int, Vector2>();

            Background = new List<Layer>();
            Foreground = new List<Layer>();
        }
        #endregion //Fields and Constructors

        #region Update
        /// <summary>
        /// Updates the backgrounds according to by how much the camera has moved.
        /// </summary>
        /// <param name="camMovement">By how much the camera has moved.</param>
        public void Update(Vector2 camMovement)
        {
            UpdateLayers(Background, camMovement);
            UpdateLayers(Foreground, camMovement);
        }

        private void UpdateLayers(List<Layer> layers, Vector2 camMovement)
        {
            int currentIndex;
            Vector2 layerSpeed;
            Point layerSize;
            Vector2 move;
            int xCount, yCount;
            foreach (Layer layer in layers)
            {
                currentIndex = layer.index;
                layerSpeed = layer.speed;
                layerSize = layer.size;
                move = camMovement * layerSpeed;
                move.Y = (float)System.Math.Round(move.Y, 2);
                yCount = layer.backgrounds.GetLength(1);
                for (int y = 0; y < yCount; y++)
                {
                    xCount = layer.backgrounds.GetLength(0);
                    for (int x = 0; x < xCount; x++)
                    {
                        Image b = layer.backgrounds[x, y];
                        b.Position -= move;
                        b.Position.Y = (float)System.Math.Round(b.Position.Y, 2);

                        //Check if this background is too far in any direction.
                        //If so, we move it to the opposite end of the layer.
                        //if (b.Position.X < -b.Size.X)
                        //    b.Position += new Vector2(layerSize.X, 0);
                        //else if (b.Position.X > layerSize.X - b.Size.X)
                        //    b.Position -= new Vector2(layerSize.X, 0);

                        if (b.Position.Y < -b.Size.Y)
                            b.Position += new Vector2(0, layerSize.Y);
                        else if (b.Position.Y > layerSize.Y - b.Size.Y)
                            b.Position -= new Vector2(0, layerSize.Y);
                    }
                }
            }
        }

        public void UpdateObject(ref float x, ref float y, Layer layer, Vector2 camMovement)
        {
            x += layer.speed.X * camMovement.X;
            y += layer.speed.Y * camMovement.Y;
        }
        #endregion //Update

        #region Background List Methods
        public void AddBackgroundLayer(Layer layer)
        {
            Background.Add(layer);
        }
        public void AddBackgroundLayer(Image[,] backgrounds, Vector2 speed, int index)
        {
            Background.Add(new Layer(backgrounds, speed, index));
        }
        public void AddForegroundLayer(Layer layer)
        {
            Foreground.Add(layer);
        }
        public void AddForegroundLayer(Image[,] foregrounds, Vector2 speed, int index)
        {
            Foreground.Add(new Layer(foregrounds, speed, index));
        }

        /// <summary>
        /// Inserts a background to a given layer. Note that the layer must first have been created.
        /// </summary>
        public bool AddBackground(Image background, Layer layer, int yIndex)
        {
            layer.backgrounds[layer.backgrounds.GetLength(0), yIndex] = background;
            return true;
        }
        /// <summary>
        /// Inserts a background to a given layer. Note that the layer must first have been created.
        /// </summary>
        public bool AddBackground(Image background, int layerIndex, int yIndex)
        {
            Layer layer = Background.FirstOrDefault(l => l.index == layerIndex);
            if (layer == null)
                return false;
            layer.backgrounds[layer.backgrounds.GetLength(0), yIndex] = background;
            return true;
        }

        /// <summary>
        /// Inserts a background to a given layer. Note that the layer must first have been created.
        /// </summary>
        public bool AddForeground(Image foreground, Layer layer, int yIndex)
        {
            layer.backgrounds[layer.backgrounds.GetLength(0), yIndex] = foreground;
            return true;
        }
        /// <summary>
        /// Inserts a background to a given layer. Note that the layer must first have been created.
        /// </summary>
        public bool AddForeground(Image foreground, int layerIndex, int yIndex)
        {
            Layer layer = Foreground.FirstOrDefault(l => l.index == layerIndex);
            if (layer == null)
                return false;
            layer.backgrounds[layer.backgrounds.GetLength(0), yIndex] = foreground;
            return true;
        }

        /// <summary> Removes all backgrounds from a given layer. </summary>
        /// <param name="layerIndex">The layer index from which to remove backgrounds.</param>
        public void RemoveBackgroundLayer(int layerIndex)
        {
            List<Layer> newLayers = new List<Layer>(Background.Count);
            foreach (Layer layer in Background.Where(l => l.index != layerIndex))
                newLayers.Add(layer);
        }
        /// <summary> Removes all backgrounds from a given layer. </summary>
        /// <param name="layerIndex">The layer index from which to remove backgrounds.</param>
        public void RemoveForegroundLayer(int layerIndex)
        {
            List<Layer> newLayers = new List<Layer>(Foreground.Count);
            foreach (Layer layer in Foreground.Where(l => l.index != layerIndex))
                newLayers.Add(layer);
        }
        /// <summary> Removes all backgrounds. </summary>
        public void Clear()
        {
            Background.Clear();
            Foreground.Clear();
        }
        #endregion //Background List Methods

        #region Helper Methods
        /// <summary>
        /// Sums up the total size of all backgrounds on a given layer index.
        /// </summary>
        /// <param name="layer">Which layer you want the size of.</param>
        /// <returns>The total size of the layer.</returns>
        //private Point LayerSize(int layer)
        //{
        //    Point layerSize = new Point();
        //    foreach (Background b in backgrounds)
        //        if (b.LayerIndex == layer)
        //            layerSize += b.Size;
        //    return layerSize;
        //}

        /// <summary>
        /// Sorts the list of backgrounds according to layer index.
        /// </summary>
        //private void SortBackgrounds()
        //{
        //    backgrounds.Sort(CompareBackgroundsByLayerIndex);
        //    int currentIndex = 0;
        //    int widthPos = 0;
        //    foreach (IBackground b in backgrounds)
        //        if (b.LayerIndex != currentIndex)
        //        {
        //            currentIndex = b.LayerIndex;
        //            b.Position.X = widthPos = 0;
        //            widthPos += b.Size.X;
        //        }
        //        else
        //        {
        //            b.Position.X = widthPos;
        //            widthPos += b.Size.X;
        //        }
        //}
        //private int CompareBackgroundsByLayerIndex(IBackground b1, IBackground b2)
        //{
        //    if (b1.LayerIndex < b2.LayerIndex) return -1;
        //    else if (b1.LayerIndex > b2.LayerIndex) return 1;
        //    else return 0;
        //}
        #endregion //Helper Methods
    }
}
